var input = File.ReadAllLines(Path.Combine(Path.GetDirectoryName(Util.CurrentQueryPath), "..", "day19.txt")).ToList();
var rules = input.TakeWhile(i => !string.IsNullOrEmpty(i)).Select(i => i.Split(':')).ToDictionary(i => int.Parse(i[0]), i => i[1]);
var messages = input.Skip(rules.Count()).Skip(1).ToList();
var compiled = rules.Where(r => r.Value.Trim().StartsWith("\"")).ToDictionary(r => r.Key, r => new[] { r.Value.Trim().Substring(1, 1) });
rules = rules.Where(r => !compiled.ContainsKey(r.Key)).ToDictionary(r => r.Key, r => r.Value);
while (rules.Any())
{
foreach (var rule in rules)
{
var deps = rule.Value.Split(" |".ToCharArray()).Where(r => !string.IsNullOrEmpty(r)).Select(int.Parse);
if (deps.All(d => compiled.ContainsKey(d)))
{
var options = new List();
foreach (var segment in rule.Value.Split('|'))
{
var dep = segment.Split(' ').Where(s => !string.IsNullOrEmpty(s)).Select(int.Parse).Select(d => compiled[d]).ToArray();
if (dep.Length > 1)
options.AddRange(from l in dep[0]
from r in dep[1]
let o =l+r
select o);
else options.AddRange(dep[0]);
}
compiled[rule.Key] = options.ToArray();
}
}
rules = rules.Where(r => !compiled.ContainsKey(r.Key)).ToDictionary(r => r.Key, r => r.Value);
}
var part1 = messages.Count(m => compiled[0].Contains(m));
part1.Dump();
int part2 = 0;
foreach (var message in messages)
{
// rule 8
var segments = compiled[42].Where(o => message.IndexOf(o) > -1).ToArray();
var rule8 = new List(segments);
string[] possibles = segments;
while (possibles.Any() && possibles.First().Length < message.Length)
{
possibles = (from s1 in segments
from s2 in possibles
let s = s1 + s2
where message.IndexOf(s) > -1
select s)
.ToArray();
rule8.AddRange(possibles);
}
// rule 11
var left = compiled[42].Where(o => message.IndexOf(o) > -1).ToArray();
var right = compiled[31].Where(o => message.IndexOf(o) > -1).ToArray();
possibles = (from l in left from r in right let o =l+r where message.IndexOf(o) > -1 select o).ToArray();
var rule11 = new List(possibles);
while (possibles.Any() && possibles.First().Length < message.Length){
possibles = (from l in left
from p in possibles
from r in right
let s = l + p + r
where message.IndexOf(s) > -1
select s)
.ToArray();
rule11.AddRange(possibles);
}
// rule 0: 8 11
if ((from a in rule8 from b in rule11 let c=a+b where c.Length == message.Length select c).Any(c => message == c))
part2++;
}
part2.Dump();